#pragma once
#include"Mutex.hpp"
#include<time.h>
#include<filesystem> // C++17 文件操作
#include<unistd.h>
#include<memory>
#include<sstream>
#include<fstream>
#include<iostream>

enum class Loglevel
{
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

std::string LevelString(Loglevel level)
{
    switch(level)
    {
        case Loglevel::DEBUG:
            return "Debug";
        case Loglevel::INFO:
            return "Info";
        case Loglevel::WARNING:
            return "Warning";
        case Loglevel::ERROR:
            return "Error";
        case Loglevel::FATAL:
            return "Fatal";
        default:
            return "Unknow";
    }
}

std::string GetTime()
{
    time_t currrttime= time(nullptr);
    struct tm currtm;
    localtime_r(&currrttime,&currtm);
    char buffer[64];
    snprintf(buffer,sizeof(buffer),"%4d-%02d-%02d %02d:%02d:%02d",
            currtm.tm_year+1900,
            currtm.tm_mon+1,
            currtm.tm_mday,
            currtm.tm_hour,
            currtm.tm_min,
            currtm.tm_sec
    );
    return buffer;
}

class LogStrategy
{
public:
    virtual ~LogStrategy() = default;
    virtual void SyncLog(const std::string &logmessage) = 0;
};

// 显示器刷新
class ConsoleLogStrategy : public LogStrategy
{
public:
    ~ConsoleLogStrategy()
    {
    }
    void SyncLog(const std::string &logmessage) override
    {
        {
            GuardMutex lockguard(&_lock);
            std::cout << logmessage << std::endl;
        }
    }

private:
    Mutex _lock;
};

const std::string logdefaultdir = "log";
const static std::string logfilename = "test.log";

class FileLogStrategy : public LogStrategy
{
public:
    FileLogStrategy(const std::string &dir = logdefaultdir,
                    const std::string filename = logfilename)
        : _dir_path_name(dir), _filename(filename)
    {
        GuardMutex lockguard(&_lock);
        if (std::filesystem::exists(_dir_path_name))
        {
            return;
        }
        try
        {
            std::filesystem::create_directories(_dir_path_name);
        }
        catch (const std::filesystem::filesystem_error &e)
        {
            std::cerr << e.what() << "\r\n";
        }
    }

    void SyncLog(const std::string &logmessage) override
    {
        {
            GuardMutex lockguard(&_lock);
            std::string target = _dir_path_name;
            target += "/";
            target += _filename;

            std::ofstream out(target.c_str(), std::ios::app); // append
            if (!out.is_open())
            {
                return;
            }
            out << logmessage << "\n"; // out.write
            out.close();
        }
    }

    ~FileLogStrategy()
    {
    }
private:
    Mutex _lock;
    std::string _dir_path_name; // log
    std::string _filename;      // hello.log => log/hello.log
};

// 网络刷新

////////////////////////////////////////////////////////

// 1. 定制刷新策略
// 2. 构建完整的日志

class Logger
{
public:
    Logger()
    {}
    void EnableConsoleLogStrategy()
    {
        _strategy = std::make_unique<ConsoleLogStrategy>();
    }
    void EnableFileLogStrategy()
    {
        _strategy = std::make_unique<FileLogStrategy>();
    }

    class LogMessage
    {
    public:
        LogMessage(Loglevel level,std::string&filename,int line,Logger& logger)
            :_curr_time(GetTime()),
            _level(level),
            _pid(getpid()),
            _line(line),
            _logger(logger)
        {
            std::stringstream ss;
            ss << "[" << _curr_time << "] "
               << "[" << LevelString(_level) << "] "
               << "[" << _pid << "] "
               << "[" << _filename << "] "
               << "[" << _line << "]"
               <<  " - ";

            _loginfo = ss.str();
        }

        template<class T>
        LogMessage& operator<<(const T&info)
        {
            std::stringstream ss;
            ss<<info;
            _loginfo+=ss.str();
            return *this;
        }
        
        ~LogMessage()
        {
            if(_logger._strategy)
            {
                _logger._strategy->SyncLog(_loginfo);
            }
        }
    private:
        std::string _curr_time; // 日志时间
        Loglevel _level; // 日志等级
        pid_t _pid; // 进程pid
        std::string _filename;
        int _line;

        std::string _loginfo; // 一条合并完成的，完整的日志信息
        Logger &_logger; // 提供刷新策略的具体做法
    };

    LogMessage operator()(Loglevel level, std::string filename, int line)
    {
        return LogMessage(level, filename, line, *this);
    }
    ~Logger()
    {}
private:
    std::unique_ptr<LogStrategy> _strategy;
};

Logger logger;

#define LOG(level) logger(level, __FILE__, __LINE__)
#define EnableConsoleLogStrategy() logger.EnableConsoleLogStrategy()
#define EnableFileLogStrategy() logger.EnableFileLogStrategy()